import React, { useEffect, useRef, useState, useCallback, useMemo } from 'react';
import { createPortal } from 'react-dom';

let instance = null;
// 定位
export default function Position(props) {
  const { children, targetRef, getPopupContainer } = props;
  const PchildrenRef = useRef();
  const parentDom = getPopupContainer && getPopupContainer();
  // targetRef 的 select 的dom
  const [style, setStyle] = useState({});

  // 计算style
  const setStyleFun = () => {
    const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = targetRef.current;
    let top = offsetTop + offsetHeight + 10;
    if (parentDom) {
      top = top - parentDom.scrollTop;
    }
    setStyle({
      position: 'absolute',
      top: top + 'px',
      left: offsetLeft + 'px',
      width: offsetWidth + 'px',
      zIndex: 99,
      background: '#fff',
      boxShadow:
        '0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d',
    });
  };

  if (!instance) {
    instance = document.createElement('div');
    instance.className = 'll-position';
    document.body.appendChild(instance);
  }

  // 执行滚动css
  // useEffect(() => {
  //   console.log('style 更新');
  //   //  PchildrenRef
  // }, [style]);

  const runStyle = () => {
    if (Object.keys(style).length) {
      for (const key in style) {
        const ins = style[key];
        PchildrenRef.current.style[key] = ins;
      }
    }
  };

  // 性能优化
  useMemo(() => {
    runStyle();
    console.log('style 更新');
  }, [style]);

  useEffect(() => {
    if (parentDom) {
      parentDom.addEventListener('scroll', setStyleFun, false);
    }
    setStyleFun();
    // 避免重复渲染定位盒子
    return () => {
      // 组件销毁是 删除instance
      if (parentDom) {
        parentDom.removeEventListener('scroll', setStyleFun, false);
      }
    };
  }, []);

  // 情况一: 在body中滚动 因为我们无法保证所渲染的区域是否存在 overflow hidden 所以我们要渲染到root 也就是 render in body
  // 情况二: 在特定元素中滚动 （body中的有个盒子设置了scroll 这个时候就不能在body中定位了 要定位到指定的父元素）
  const dom = () => {
    console.log('渲染一次');
    return (
      <div className="positionBox" ref={PchildrenRef}>
        {children}
      </div>
    );
  };
  // 缓存组件 避免不必要的更新 在这里组件只会触发style更改 防止父组件变化引起自组件刷新
  const memoDom = useMemo(dom, []);
  // createPortal 把指定dom 塞入到portalDom
  return createPortal(memoDom, instance);
}
